
/*
 * sndpipe: A UNIX pipes-based audio stream processor toolkit.
 * Copyright (C) 2011  Bradley Worley
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to:
 *
 *   Free Software Foundation, Inc.
 *   51 Franklin Street, Fifth Floor
 *   Boston, MA  02110-1301, USA.
 */

/* include the sndpipe header. */
#include "sndpipe.h"

/* func_blk: initiates the BLK functionality.
 *
 * this function opens up an input and output pipe (both are required),
 * places a new channel at the beginning of its output pipe, and writes
 * timebase information to the new channel, copying over the old data.
 */
void func_blk (void) {
  /* declare required variables. */
  unsigned long c, i, frames;
  struct pipes *pi, *po;
  double **buf;
  SF_INFO sfi;

  /* declare required blocking variables. */
  unsigned long blocks;
  double duration;

  /* zero out the sndfile information structure. */
  memset (&sfi, 0, sizeof (sfi));

  /* attempt to open the input pipe. */
  pi = pipes_open_input ();

  /* ensure the input pipe was successfully opened. */
  if (!pi) {
    /* print a failure message and exit the application. */
    failf ("unable to open input pipe");
  }

  /* set the output pipe options from the input pipe, adding a channel. */
  sfi.samplerate = pi->sfi.samplerate;
  sfi.channels = pi->sfi.channels + 1;
  sfi.format = pi->sfi.format;

  /* ensure we have an output format. */
  if (!sfi.format) {
    /* print a failure message and exit the application. */
    failf ("unable to retrieve pipes output format");
  }

  /* open the output pipes structure. */
  po = pipes_open_output (sfi);

  /* read in the block buffer size and duration options. */
  blocks = opts_get_int (OPTS_S_BUFFER);
  duration = opts_get_float (OPTS_S_DURATION);

  /* if the duration was specified, recalculate the block size. */
  if (duration)
    blocks = floor ((double) po->sfi.samplerate * duration);

  /* ensure we have a sane blocks buffer size. */
  if (!blocks) {
    /* print a warning message and set the default value. */
    warnf ("unknown block buffer size. assuming 1024 frames");
    blocks = 1024;
  }

  /* allocate the pipes buffer memory. */
  frames = blocks;
  buf = pipes_buf_alloc (po, &frames);

  /* loop while we can write samples to the pipe. */
  do {
    /* attempt to read from the input pipe. */
    if (pipes_read (pi, &buf, frames) != SP_OK) {
      /* print a failure message and break the loop. */
      warnf ("unable to read from input audio pipe");
      break;
    }

    /* loop through the number of data frames. */
    for (i = 0; i < frames; i++) {
      /* and through the number of channels, shifting the input data. */
      for (c = po->sfi.channels - 1; c > 0; c--)
        buf[c][i] = buf[c - 1][i];

      /* set the value in the timebase channel. */
      buf[0][i] = 1.0 * (i == 0);
    }
  } while (pipes_write (po, buf, frames) == SP_OK);

  /* free the output pipes buffer memory. */
  pipes_buf_free (po, frames, buf);

  /* attempt to close the input pipe. */
  if (pipes_close (pi) != SP_OK) {
    /* print a failure message and exit the application. */
    failf ("unable to close input pipe");
  }

  /* attempt to close the output pipe. */
  if (pipes_close (po) != SP_OK) {
    /* print a failure message and exit the application. */
    failf ("unable to close output pipe");
  }
}

